use std::sync::Arc;

use axum_app_common::{model::AppState, ServiceStore};
use axum_app_service::{
    service::{rbac_svc, role_svc, user_svc},
    UserStatus,
};
use tracing::{debug, error, info};

pub mod handler;
pub mod middleware;
pub mod model;

pub async fn rbac_setup(state: &AppState, service_store: Arc<ServiceStore>) {
    let resource_svc =
        axum_app_service::service::resource_svc::ResourceSvc::new(&state.db_conn, None);
    let rbac_svc = rbac_svc::RbacSvc::new(&state.db_conn, None);

    let res_type_service = "service";

    // 初始内置资源 ,数据为来自service_store中的注册服务
    let mut service_list = vec![];
    for (k, v) in service_store.get_service_store_info() {
        match resource_svc
            .create_resource(res_type_service, k.as_str(), v.as_str(), Some(v.as_str()))
            .await
        {
            Ok(_) => info!("资源: {k}({v}) 写入成功"),
            Err(e) => {
                debug!("写入资源: {k}({v}) 失败: {e}");
            }
        };
        service_list.push(k);
    }

    let user_svc = user_svc::UserSvc::new(&state.db_conn, None);
    // 初始一个内置角色 admin
    let role_admin = "ADMIN";
    let role_service = role_svc::RoleSvc::new(&state.db_conn, None);
    let _ = role_service
        .create(role_admin, "管理员", "管理员角色")
        .await;

    // 资源到角色的关系绑定
    let service_list = service_list.iter().map(|s| s.as_str()).collect::<Vec<_>>();
    println!("资源到角色的关系绑定:{:?}", service_list);
    let _ = rbac_svc
        .bind_role_resources(role_admin, res_type_service, &service_list)
        .await;

    // 初始一个内置用户 admin 将上述的角色分配给该用户
    let _ = user_svc
        .create(
            "admin",
            "管理员",
            None,
            Some("123123"),
            Some(UserStatus::Active),
        )
        .await;
    // 内置角色与用户关系绑定
    let admin_user = user_svc.find_by_username("admin").await;
    match admin_user {
        Ok(Some(user)) => {
            info!("内置角色与用户关系绑定");
            let _ = rbac_svc.bind_user_roles(&user.userid, &[role_admin]).await;
        }
        Ok(None) => error!("未找到用户信息"),
        Err(err) => error!("查询admin用户信息异常: {}", err),
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;

    use axum_app_common::model::AppState;

    use crate::handler;
    use crate::rbac_setup;

    #[tokio::test]
    async fn test_rbac_setup() {
        let db = axum_app_common::test::get_connect().await;

        let redis_pool = axum_app_common::database::redis_conn_pool_from_env().unwrap();

        let state = AppState {
            db_conn: db,
            redis_conn_pool: redis_pool,
        };
        let service_store = handler::api_handler::regist_handlers();

        rbac_setup(&state, Arc::new(service_store)).await;
    }
}
